{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Installation\n",
    "Just pip install:\n",
    "\n",
    "```pip install omegaconf```\n",
    "\n",
    "If you want to try this notebook after checking out the repository be sure to run \n",
    "```python setup.py develop``` at the repository root before running this code."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Creating OmegaConf objects\n",
    "### Empty"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{}\n"
     ]
    }
   ],
   "source": [
    "from omegaconf import OmegaConf\n",
    "conf = OmegaConf.create()\n",
    "print(conf)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### From a dictionary"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "k: v\n",
      "list:\n",
      "- 1\n",
      "- a: '1'\n",
      "  b: '2'\n",
      "\n"
     ]
    }
   ],
   "source": [
    "conf = OmegaConf.create(dict(k='v',list=[1,dict(a='1',b='2')]))\n",
    "print(OmegaConf.to_yaml(conf))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### From a list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "- 1\n",
      "- a: 10\n",
      "  b:\n",
      "    a: 10\n",
      "\n"
     ]
    }
   ],
   "source": [
    "conf = OmegaConf.create([1, dict(a=10, b=dict(a=10))])\n",
    "print(OmegaConf.to_yaml(conf))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### From a yaml file"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "server:\n",
      "  port: 80\n",
      "log:\n",
      "  file: ???\n",
      "  rotation: 3600\n",
      "users:\n",
      "- user1\n",
      "- user2\n",
      "\n"
     ]
    }
   ],
   "source": [
    "conf = OmegaConf.load('../source/example.yaml')\n",
    "print(OmegaConf.to_yaml(conf))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### From a yaml string"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a: b\n",
      "b: c\n",
      "list:\n",
      "- item1\n",
      "- item2\n",
      "\n"
     ]
    }
   ],
   "source": [
    "yaml = \"\"\"\n",
    "a: b\n",
    "b: c\n",
    "list:\n",
    "- item1\n",
    "- item2\n",
    "\"\"\"\n",
    "conf = OmegaConf.create(yaml)\n",
    "print(OmegaConf.to_yaml(conf))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### From a dot-list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a:\n",
      "  aa:\n",
      "    aaa: 1\n",
      "    bbb: 2\n",
      "  bb:\n",
      "    aaa: 3\n",
      "    bbb: 4\n",
      "\n"
     ]
    }
   ],
   "source": [
    "dot_list = [\"a.aa.aaa=1\", \"a.aa.bbb=2\", \"a.bb.aaa=3\", \"a.bb.bbb=4\"]\n",
    "conf = OmegaConf.from_dotlist(dot_list)\n",
    "print(OmegaConf.to_yaml(conf))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### From command line arguments\n",
    "\n",
    "To parse the content of sys.arg:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "server:\n",
      "  port: 82\n",
      "log:\n",
      "  file: log2.txt\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# Simulating command line arguments\n",
    "import sys\n",
    "sys.argv = ['your-program.py', 'server.port=82', 'log.file=log2.txt']\n",
    "conf = OmegaConf.from_cli()\n",
    "print(OmegaConf.to_yaml(conf))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Access and manipulation\n",
    "Input yaml file:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "server:\n",
      "  port: 80\n",
      "log:\n",
      "  file: ???\n",
      "  rotation: 3600\n",
      "users:\n",
      "- user1\n",
      "- user2\n",
      "\n"
     ]
    }
   ],
   "source": [
    "conf = OmegaConf.load('../source/example.yaml')\n",
    "print(OmegaConf.to_yaml(conf))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Object style access:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "80"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conf.server.port"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### dictionary style access"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3600"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conf['log']['rotation']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### items in list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'user1'"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conf.users[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Changing existing keys"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "conf.server.port = 81"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Adding new keys"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "conf.server.hostname = \"localhost\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Adding a new dictionary"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "conf.database = {'hostname': 'database01', 'port': 3306}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### providing default values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'a default value'"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "conf.missing_key or 'a default value'\n",
    "conf.get('missing_key', 'a default value')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Accessing mandatory values\n",
    "Accessing fields with the value *???* will cause a MissingMandatoryValue exception.\n",
    "Use this to indicate that the value must be set before accessing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [],
   "source": [
    "import pytest\n",
    "from omegaconf import MissingMandatoryValue\n",
    "\n",
    "with pytest.raises(MissingMandatoryValue):\n",
    "    conf.log.file"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Variable interpolation\n",
    "\n",
    "OmegaConf support variable interpolation, Interpolations are evaluated lazily on access.\n",
    "\n",
    "### Config node interpolation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Interpolations are evaluated lazily on field access.<br>\n",
    "Note below that when printed the interpolations are not resolved.<br>\n",
    "They get resolved once you access them."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "server:\n",
      "  host: localhost\n",
      "  port: 80\n",
      "client:\n",
      "  url: http://${server.host}:${server.port}/\n",
      "  server_port: ${server.port}\n",
      "\n"
     ]
    }
   ],
   "source": [
    "conf = OmegaConf.load('../source/config_interpolation.yaml')\n",
    "print(OmegaConf.to_yaml(conf))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "conf.client.server_port:  80 int\n",
      "conf.client.url:  http://localhost:80/ str\n"
     ]
    }
   ],
   "source": [
    "# Primitive interpolation types are inherited from the referenced value\n",
    "print(\"conf.client.server_port: \", conf.client.server_port, type(conf.client.server_port).__name__)\n",
    "# Composite interpolation types are always string\n",
    "print(\"conf.client.url: \", conf.client.url, type(conf.client.url).__name__)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "to_yaml will resolve interpolation if `resolve=True` is passed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "server:\n",
      "  host: localhost\n",
      "  port: 80\n",
      "client:\n",
      "  url: http://localhost:80/\n",
      "  server_port: 80\n",
      "\n"
     ]
    }
   ],
   "source": [
    "print(OmegaConf.to_yaml(conf, resolve=True))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Environment variable interpolation\n",
    "\n",
    "Environment variable interpolation is also supported.\n",
    "\n",
    "Input yaml file:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Let's set up the environment first (Only needed for this demonstration)\n",
    "import os\n",
    "os.environ['USER'] = 'omry'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Here is an example config file interpolates with the USER environment variable:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "user:\n",
      "  name: ${env:USER}\n",
      "  home: /home/${env:USER}\n",
      "\n"
     ]
    }
   ],
   "source": [
    "conf = OmegaConf.load('../source/env_interpolation.yaml')\n",
    "print(OmegaConf.to_yaml(conf))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "user:\n",
      "  name: omry\n",
      "  home: /home/omry\n",
      "\n"
     ]
    }
   ],
   "source": [
    "conf = OmegaConf.load('../source/env_interpolation.yaml')\n",
    "print(OmegaConf.to_yaml(conf, resolve=True))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also set a default value for environment variables:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "42\n"
     ]
    }
   ],
   "source": [
    "conf = OmegaConf.create({\"user\" : {\"age\" : \"${env:AGE, 42}\"}})\n",
    "print(conf.user.age)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Custom interpolations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can add additional interpolation types using custom resolvers. This example creates a resolver that adds 10 the the given value."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1000\n"
     ]
    }
   ],
   "source": [
    "OmegaConf.register_resolver(\"plus_10\", lambda x: int(x) + 10)\n",
    "conf = OmegaConf.create({'key': '${plus_10:990}'})\n",
    "print(conf.key)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Merging configurations\n",
    "Merging configurations enables the creation of reusable configuration files for each logical component instead of a single config file for each variation of your task.\n",
    "\n",
    "Machine learning experiment example:\n",
    "```python\n",
    "conf = OmegaConf.merge(base_cfg, model_cfg, optimizer_cfg, dataset_cfg)\n",
    "```\n",
    "\n",
    "Web server configuration example:\n",
    "\n",
    "```python\n",
    "conf = OmegaConf.merge(server_cfg, plugin1_cfg, site1_cfg, site2_cfg)\n",
    "```\n",
    "\n",
    "The following example creates two configs from files, and one from the cli. It then combines them into a single object. Note how the port changes to 82, and how the users lists are combined."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "server:\n",
      "  port: 80\n",
      "users:\n",
      "- user1\n",
      "- user2\n",
      "\n"
     ]
    }
   ],
   "source": [
    "base_conf = OmegaConf.load('../source/example2.yaml')\n",
    "print(OmegaConf.to_yaml(base_conf))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "log:\n",
      "  file: log.txt\n",
      "\n"
     ]
    }
   ],
   "source": [
    "second_conf = OmegaConf.load('../source/example3.yaml')\n",
    "print(OmegaConf.to_yaml(second_conf))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "pycharm": {
     "name": "#%%\n"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "server:\n",
      "  port: 82\n",
      "users:\n",
      "- user1\n",
      "- user2\n",
      "log:\n",
      "  file: log.txt\n",
      "\n"
     ]
    }
   ],
   "source": [
    "from omegaconf import OmegaConf\n",
    "import sys\n",
    "\n",
    "# Merge configs:\n",
    "conf = OmegaConf.merge(base_conf, second_conf)\n",
    "\n",
    "# Simulate command line arguments\n",
    "sys.argv = ['program.py', 'server.port=82']\n",
    "# Merge with cli arguments\n",
    "conf.merge_with_cli()\n",
    "print(OmegaConf.to_yaml(conf))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.1"
  },
  "pycharm": {
   "stem_cell": {
    "cell_type": "raw",
    "metadata": {
     "collapsed": false
    },
    "source": []
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
